﻿// This shader is converted from 
// Heartfelt(https://www.shadertoy.com/view/ltffzl) - by Martijn Steinrucken aka BigWings - 2017
// countfrolic@gmail.com
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

Shader "Custom/NormalRaindrop" {
	Properties {
		_MainTex("Albedo (RGB)", 2D) = "white" {}
        _ScreenWidth("Screen Width", float) = 0
        _ScreenHeight("Screen Height", float) = 0
        _RainSpeed("Rain Speed", Range(0.1, 5)) = 0.25
        _RainAmount("Rain Amount", Range(0.1, 1)) = 0.2
        _RainBlur("Rain Blur", Range(0, 1)) = 0
        _RangeAmount("Range Amount", Range(0, 1)) = 0.2
        _RangeRadius("Range Radius", Range(0, 1)) = 0
        _WiperStart("Wiper Start", Range(0, 1)) = 0
        _WiperAmount("Wiper Amount", Range(0, 1)) = 0
        _WiperAngle("Wiper Angle", Range(0, 90)) = 0
        _WiperAxis("Wiper Axis", int) = 0
	}
	SubShader {
		Tags { "RenderType"="Opaque" "Queue" = "Transparent" }
		LOD 200
        GrabPass{"_GrabTexture"}
		Pass{
			CGPROGRAM
            #pragma enable_d3d11_debug_symbols
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"

            struct appdata {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f {
                float4 pos : POSITION;
                float2 uv : TEXCOORD0;
                float4 grabUV : TEXCOORD1;
            };


			sampler2D _MainTex;
            sampler2D _GrabTexture;
            float _ScreenWidth;
            float _ScreenHeight;
            float _RainSpeed;
            float _RainAmount;
            float _RainBlur;
            float _RangeAmount;
            float _RangeRadius;
            float _WiperStart;
            float _WiperAmount;
            float _WiperAngle;
            float _WiperAxis;

			#define S(a, b, t) smoothstep(a, b, t)

            float InRange(float2 origin, float2 uv)
            {
                float lo = uv.y * tan(radians(_WiperAngle));
                float loRet = step((uv.x - origin.x), lo);

                float hi = (uv.x - origin.x) * tan(radians(_WiperAngle));
                float hiRet = step(uv.y, hi);

                float len = length(uv - origin);
                return step(len, _RangeRadius) * lerp(hiRet, loRet, _WiperAxis);
            }


			float3 N13(float p) {
				float3 p3 = frac(float3(p, p, p) * float3(.1031, .11369, .13787));
				p3 += dot(p3, p3.yzx + 19.19);
				return frac(float3((p3.x + p3.y)*p3.z, (p3.x + p3.z)*p3.y, (p3.y + p3.z)*p3.x));
			}

			float4 N14(float t) {
				return frac(sin(t*float4(123., 1024., 1456., 264.))*float4(6547., 345., 8799., 1564.));
			}
			float N(float t) {
				return frac(sin(t*12345.564)*7658.76);
			}

			float Saw(float b, float t) {
				return S(0., b, t)*S(1., b, t);
			}

			float2 DropLayer2(float2 uv, float t) {
				float2 UV = uv;

				uv.y += t*0.75;
				float2 a = float2(6., 1.);
				float2 grid = a*2.;
				float2 id = floor(uv*grid);

				float colShift = N(id.x);
				uv.y += colShift;

				id = floor(uv*grid);
				float3 n = N13(id.x*35.2 + id.y*2376.1);
				float2 st = frac(uv*grid) - float2(.5, 0);

				float x = n.x - .5;

				float y = UV.y*20.;
				float wiggle = sin(y + sin(y));
				x += wiggle*(.5 - abs(x))*(n.z - .5);
				x *= .7;
				float ti = frac(t + n.z);
				y = (Saw(.85, ti) - .5)*.9 + .5;
				float2 p = float2(x, y);

				float d = length((st - p)*a.yx);

				float mainDrop = S(.4, .0, d);

				float r = sqrt(S(1., y, st.y));
				float cd = abs(st.x - x);
				float trail = S(.23*r, .15*r*r, cd);
				float trailFront = S(-.02, .02, st.y - y);
				trail *= trailFront*r*r;

				y = UV.y;
				float trail2 = S(.2*r, .0, cd);
				float droplets = max(0., (sin(y*(1. - y)*120.) - st.y))*trail2*trailFront*n.z;
				y = frac(y*10.) + (st.y - .5);
				float dd = length(st - float2(x, y));
				droplets = S(.3, 0., dd);
				float m = mainDrop + droplets*r*trailFront;

				return float2(m, trail);
			}

			float StaticDrops(float2 uv, float t) {
				uv *= 40.;

				float2 id = floor(uv);
				uv = frac(uv) - .5;
				float3 n = N13(id.x*107.45 + id.y*3543.654);
				float2 p = (n.xy - .5)*.7;
				float d = length(uv - p);

				float fade = Saw(.025, frac(t + n.z));
				float c = S(.3, 0., d)*frac(n.z*10.)*fade;
				return c;
			}

			float2 Drops(float2 uv, float t, float l0, float l1, float l2) {
				float s = StaticDrops(uv, t)*l0;
				float2 m1 = DropLayer2(uv, t)*l1;
				float2 m2 = DropLayer2(uv*1.85, t)*l2;

				float c = s + m1.x + m2.x;
				c = S(.3, 1., c);

				return float2(c, max(m1.y*l0, m2.y*l1));
			}

            float2 BlurUV(float2 uv) {
                float2 blurUV = uv;
                float fade = 1 - saturate(fwidth(blurUV) * 60);
                float blur = _RainBlur * 7 * (1 - fade);
                blur *= 0.01;
                float a = N(blurUV) * 6.2831;
                const float numSample = 16;
                for (float i = 0; i < numSample; i++) {
                    float2 offs = float2(sin(a), cos(a)) * blur;
                    float d = frac(sin((i+1)*546.)*5425.);
                    d = sqrt(d);
                    offs *= d;
				    blurUV += offs;
                    a++;
                }

                return blurUV;
            }

            float3 dropMainTexture(sampler2D tex, float2 textUV , float2 mainUV) {
                textUV = BlurUV(textUV);
                mainUV = BlurUV(mainUV);

                float2 leftDown = float2(_WiperStart, 0);
                float width = lerp(_ScreenWidth, 1, step(_ScreenWidth, 0));
                float height = lerp(_ScreenHeight, 1, step(_ScreenHeight, 0));
                //float dist = width / height * .5;
                float2 middleDown = float2(_WiperStart + _RangeRadius, 0);
                float2 uv = (mainUV * float2(width, height)) / height;
				float2 UV = textUV.xy;
				float T = fmod(_Time.y, 102.);

				float t = T*.2;
                float maxBlur = lerp(3., 6., 0);
                float minBlur = 2.;
                float story = S(0, 70., T);
                minBlur = 4. + S(.5, 1., story) * 3.;
                maxBlur = 6. + S(.5, 1., story) * 1.5;

                float2 origin = lerp(leftDown, middleDown, step(_RangeRadius, uv.x));
                float len = length(uv - origin);
                float heart = lerp(_RainAmount, _RangeAmount, step(len, _RangeRadius));
                int ret = InRange(origin, uv);
                heart = lerp(heart, _WiperAmount, ret);

                maxBlur -= heart;

				uv *= 1.5;								// zoom out a bit more
				t *= _RainSpeed;

				float staticDrops = S(-.5, 1., heart)*2.;
				float layer1 = S(.25, .75, heart);
				float layer2 = S(.0, .5, heart);

				float2 c = Drops(uv, t, staticDrops, layer1, layer2);
				float2 e = float2(.001, 0.);
				float cx = Drops(uv + e, t, staticDrops, layer1, layer2).x;
				float cy = Drops(uv + e.yx, t, staticDrops, layer1, layer2).x;
				float2 n = float2(cx - c.x, cy - c.x);		// expensive normals
                float2 texCoord = float2(UV.x + n.x, UV.y + n.y);
                float3 col = tex2D(tex, texCoord).rgb;
                return col;
            }

            v2f vert(appdata v) {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.grabUV = UNITY_PROJ_COORD(ComputeGrabScreenPos(o.pos));
                return o;
            }

			fixed4 frag(v2f i) : SV_Target {
                float3 mainCol = tex2D(_MainTex, i.uv);
                float2 projUV = i.grabUV / i.grabUV.w;
                float3 dropCol = dropMainTexture(_GrabTexture, projUV, i.uv);
                float3 blurCol = float3(1, 1, 1);
                float3 col = mainCol * lerp(.3, .2, _RainBlur) + blurCol * lerp(.0, .2, _RainBlur) + dropCol * lerp(.7, .6, _RainBlur);

				return fixed4(col, 1);
			}
			ENDCG
		}
	}
	FallBack "Diffuse"
}